<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
  <meta name="renderer" content="webkit">

  
  <title>Android 14 init进程解析 | 龙之叶的博客</title>

  <link rel="shortcut icon" href="/images/favicon.png">
  <link rel="alternate" href="/atom.xml" title="龙之叶的博客" type="application/atom+xml">
  <meta name="description" content="Android 14 init进程解析">
<meta property="og:type" content="article">
<meta property="og:title" content="Android 14 init进程解析">
<meta property="og:url" content="http://longzhiye.top/2024/02/25/2024-02-25/index.html">
<meta property="og:site_name" content="龙之叶的博客">
<meta property="og:description" content="Android 14 init进程解析">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://longzhiye.top/images/20240225/20240225001.png">
<meta property="og:image" content="http://longzhiye.top/images/20240225/20240225001.png">
<meta property="article:published_time" content="2024-02-24T16:00:00.000Z">
<meta property="article:modified_time" content="2024-08-29T02:40:34.924Z">
<meta property="article:author" content="龙之叶">
<meta property="article:tag" content="Android">
<meta property="article:tag" content="Linux">
<meta property="article:tag" content="framework">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://longzhiye.top/images/20240225/20240225001.png">

  <meta name="keywords" content=",Android,Linux,framework">
  <meta name="format-detection" content="telephone=no,email=no">
  <meta name="theme-color" content="#9C27B0">

  <meta name="mobile-web-app-capable" content="yes">
  <meta name="application-name" content="龙之叶的博客">
  <meta name="msapplication-starturl" content="http://longzhiye.top/2024/02/25/2024-02-25/">
  <meta name="msapplication-navbutton-color" content="#9C27B0">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-title" content="龙之叶的博客">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="apple-touch-icon" href="/images/favicon.png">

  
    <link rel="canonical" href="http://longzhiye.top/2024/02/25/2024-02-25/">
  

  
  

  
  
  

  
<link rel="stylesheet" href="/css/mdui.css">
<link rel="stylesheet" href="/css/style.css">

  
<link rel="stylesheet" href="/custom.css">

<meta name="generator" content="Hexo 5.4.2"></head>

<body class="mdui-appbar-with-toolbar mdui-theme-primary-indigo mdui-theme-accent-pink">
  <script>var a=localStorage.getItem("mdui-theme-layout-dark");if(a){document.getElementsByTagName("body")[0].className+=" mdui-theme-layout-dark"};</script>
  <script>if(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches){document.getElementsByTagName("body")[0].className+=" mdui-theme-layout-dark"};</script>
  <script>var a=localStorage.getItem("mdui-drawer-close");if(!a){document.getElementsByTagName("body")[0].className+=" mdui-drawer-body-left"};</script>
  <header id="header" class="mdui-appbar mdui-appbar-fixed mdui-appbar-scroll-hide mdui-appbar-inset">
  <div class="mdui-toolbar mdui-color-theme">
    <a href="javascript:;" class="mdui-btn mdui-btn-icon" mdui-drawer="{target: '#sidebar', swipe: true}"><i class="mdui-icon material-icons">menu</i></a>
    <a href="/" class="mdui-typo-headline">龙之叶的博客</a>
    <div class="mdui-toolbar-spacer"></div>
    <a href="javascript:;" class="mdui-btn mdui-btn-icon" mdui-dialog="{target: '#search'}" mdui-tooltip="{content: '搜索'}"><i class="mdui-icon material-icons">search</i></a>
	<!--
    <a href="/atom.xml" class="mdui-btn mdui-btn-icon" mdui-tooltip="{content: 'RSS'}"><i class="mdui-icon material-icons">rss_feed</i></a>
	-->
  </div>
</header>
<div class="mdui-dialog" id="search">
  
    <div class="search-form">
      <input type="search" class="search-form-input" placeholder="请输入关键字">
    </div>
    <div class="search-result" data-resource="/search.xml"></div>
  
</div>

  <aside id="sidebar" class="mdui-drawer mdui-drawer-full-height">
  <script>var a=localStorage.getItem("mdui-drawer-close");if(a){document.getElementById("sidebar").className+=" mdui-drawer-close"};</script>
  <div class="mdui-grid-tile">
    <img src="/images/banner.png" style="height: 160px;">
    <img src="/images/avatar.png" class="avatar-animation" style="position: absolute; top: 10%; left: 24px; width: 64px; height: 64px; border: 2px solid #fff; border-radius: 50%;background-color:#fff;">
    <div class="mdui-grid-tile-actions">
      <div class="mdui-grid-tile-text">
        <div class="mdui-grid-tile-title">龙之叶</div>
        <div class="mdui-grid-tile-subtitle"><i class="mdui-icon material-icons">art_track</i>生命不息，折腾不止</div>
      </div>
      
        <div class="mdui-grid-tile-buttons">
          <a href="mailto:longzhiye163@163.com" class="mdui-btn mdui-btn-icon" mdui-tooltip="{content: 'longzhiye163@163.com'}"><i class="mdui-icon material-icons">email</i></a>
        </div>
      
    </div>
  </div>

  <div class="mdui-list" mdui-collapse="{accordion: true}">
    <a href="/" class="mdui-list-item mdui-ripple">
      <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-blue">home</i>
      <div class="mdui-list-item-content">主页</div>
    </a>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-0");if(a){document.getElementsByClassName("mdui-collapse-item")[0].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-deep-orange">archive</i>
        <div class="mdui-list-item-content">归档</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/archives/2025/07/">七月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/06/">六月 2025<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/03/">三月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/02/">二月 2025<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2025/01/">一月 2025<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/10/">十月 2024<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/09/">九月 2024<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/08/">八月 2024<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/03/">三月 2024<span class="mdui-ripple sidebar_archives-count">5</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/02/">二月 2024<span class="mdui-ripple sidebar_archives-count">11</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2024/01/">一月 2024<span class="mdui-ripple sidebar_archives-count">9</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/12/">十二月 2023<span class="mdui-ripple sidebar_archives-count">10</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/11/">十一月 2023<span class="mdui-ripple sidebar_archives-count">8</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/10/">十月 2023<span class="mdui-ripple sidebar_archives-count">8</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/09/">九月 2023<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/08/">八月 2023<span class="mdui-ripple sidebar_archives-count">6</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/06/">六月 2023<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/05/">五月 2023<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/04/">四月 2023<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/03/">三月 2023<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2023/02/">二月 2023<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2022/09/">九月 2022<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2022/08/">八月 2022<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/04/">四月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/03/">三月 2017<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/02/">二月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2017/01/">一月 2017<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/12/">十二月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/11/">十一月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/10/">十月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/archives/2016/08/">八月 2016<span class="mdui-ripple sidebar_archives-count">1</span></a>
        
      </div>
    </div>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-1");if(a){document.getElementsByClassName("mdui-collapse-item")[1].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-green">class</i>
        <div class="mdui-list-item-content">分类</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术<span class="mdui-ripple sidebar_archives-count">98</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E7%94%9F%E6%B4%BB/">生活<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/categories/%E9%80%9A%E7%9F%A5/">通知<span class="mdui-ripple sidebar_archives-count">4</span></a>
        
      </div>
    </div>
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-2");if(a){document.getElementsByClassName("mdui-collapse-item")[2].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-brown">bookmark</i>
        <div class="mdui-list-item-content">标签</div>
        <i class="mdui-collapse-item-arrow mdui-icon material-icons">keyboard_arrow_down</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
        <a class="mdui-ripple sidebar_archives-link" href="/tags/ANR/" rel="tag">ANR<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/APP/" rel="tag">APP<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android/" rel="tag">Android<span class="mdui-ripple sidebar_archives-count">89</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android12/" rel="tag">Android12<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android13/" rel="tag">Android13<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Android14/" rel="tag">Android14<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/AndroidStudio/" rel="tag">AndroidStudio<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/AutoDraw/" rel="tag">AutoDraw<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Crash/" rel="tag">Crash<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Foxmail/" rel="tag">Foxmail<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Framework/" rel="tag">Framework<span class="mdui-ripple sidebar_archives-count">20</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/GPS%E8%BD%A8%E8%BF%B9%E5%9B%BE/" rel="tag">GPS轨迹图<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Git/" rel="tag">Git<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/GitHub/" rel="tag">GitHub<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Google/" rel="tag">Google<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Hexo/" rel="tag">Hexo<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Java/" rel="tag">Java<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Kernel/" rel="tag">Kernel<span class="mdui-ripple sidebar_archives-count">4</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Launcher/" rel="tag">Launcher<span class="mdui-ripple sidebar_archives-count">17</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Lib/" rel="tag">Lib<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Linux/" rel="tag">Linux<span class="mdui-ripple sidebar_archives-count">18</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Markdown/" rel="tag">Markdown<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Material-Design/" rel="tag">Material Design<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/OS-X/" rel="tag">OS X<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/OTA/" rel="tag">OTA<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/QuickTime/" rel="tag">QuickTime<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/SSH/" rel="tag">SSH<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Settings/" rel="tag">Settings<span class="mdui-ripple sidebar_archives-count">6</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/SystemUI/" rel="tag">SystemUI<span class="mdui-ripple sidebar_archives-count">19</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Ubuntu/" rel="tag">Ubuntu<span class="mdui-ripple sidebar_archives-count">7</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/WPS/" rel="tag">WPS<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Wifi/" rel="tag">Wifi<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/WindTerm/" rel="tag">WindTerm<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/Windows/" rel="tag">Windows<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/androidmk/" rel="tag">androidmk<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/blog/" rel="tag">blog<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/build/" rel="tag">build<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/feel/" rel="tag">feel<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/framework/" rel="tag">framework<span class="mdui-ripple sidebar_archives-count">50</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/git/" rel="tag">git<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/inotify/" rel="tag">inotify<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/life/" rel="tag">life<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/ninja/" rel="tag">ninja<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/rsync/" rel="tag">rsync<span class="mdui-ripple sidebar_archives-count">2</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/standard/" rel="tag">standard<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/test/" rel="tag">test<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1/" rel="tag">企业微信<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag">操作系统<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%B5%8B%E8%AF%95/" rel="tag">测试<span class="mdui-ripple sidebar_archives-count">1</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E6%BA%90%E7%A0%81/" rel="tag">源码<span class="mdui-ripple sidebar_archives-count">3</span></a><a class="mdui-ripple sidebar_archives-link" href="/tags/%E7%94%9F%E6%B4%BB%E6%84%9F%E6%82%9F/" rel="tag">生活感悟<span class="mdui-ripple sidebar_archives-count">1</span></a>
        
      </div>
    </div>
    <a href="/about" class="mdui-list-item mdui-ripple">
      <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-purple">person</i>
      <div class="mdui-list-item-content">关于</div>
    </a>
  </div>

  <div class="mdui-divider"></div>

  <div class="mdui-list" mdui-collapse="{accordion: true}">
    
      <a href="/timeline" class="mdui-list-item mdui-ripple">时间轴</a>
    
    <div class="mdui-collapse-item">
      <script>var a=localStorage.getItem("mdui-collapse-item-3");if(a){document.getElementsByClassName("mdui-collapse-item")[3].className+=" mdui-collapse-item-open"};</script>
      <div class="mdui-collapse-item-header mdui-list-item mdui-ripple">
        <div class="mdui-list-item-content">友情链接</div>
        <i class="mdui-list-item-icon mdui-icon material-icons">link</i>
      </div>
      <div class="mdui-collapse-item-body mdui-list mdui-list-dense">
        
          <a href="http://www.niemingzhao.top" target="_blank" class="mdui-list-item mdui-p-l-2 mdui-text-color-theme-accent mdui-ripple" style="justify-content: center;">聂明照的博客</a>
        
        
      </div>
    </div>
  </div>
</aside>

  <main id="main" class="mdui-m-t-5 fadeIn animated">
  
<link rel="stylesheet" href="//cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css">

  <style>#main article .mdui-card-content .center-block{display:block!important;margin-right:auto!important;margin-left:auto!important}</style>
  <style>#main article .mdui-card-content .text-center{text-align:center!important}</style>
  <article class="mdui-card mdui-m-b-5">
    <header class="mdui-card-media">
      <img src="/images/random/material-12.png" style="max-height: 240px;">
      <div class="mdui-card-media-covered">
        <div class="mdui-card-primary">
          <div class="mdui-card-primary-title">Android 14 init进程解析</div>
          <div class="mdui-card-primary-subtitle"><i class="iconfont">&#xe697;</i> 2024-02-25 / <i class="iconfont">&#xe601;</i> 龙之叶 &nbsp;&nbsp; <span id="busuanzi_container_page_pv" style="display: none;"><i class="iconfont">&#xe7fd;</i> <span id="busuanzi_value_page_pv"></span></span></div>
        </div>
      </div>
      <div class="mdui-card-menu">
        
          <button class="mdui-btn mdui-btn-icon mdui-text-color-white" mdui-menu="{target: '#qrcode', align: 'right'}"><i class="mdui-icon material-icons">devices</i></button>
          <ul class="mdui-menu" id="qrcode">
            
              <li class="mdui-menu-item"><a class="mdui-text-center mdui-ripple">发送到手机</a></li>
            
            <li class="mdui-menu-item" disabled>
              
                <img src="//qr.liantu.com/api.php?w=246&m=10&text=http://longzhiye.top/2024/02/25/2024-02-25/">
              
            </li>
          </ul>
        
        
          <button class="mdui-btn mdui-btn-icon mdui-text-color-white" mdui-menu="{target: '#share_menu', align: 'right'}"><i class="mdui-icon material-icons">share</i></button>
          <ul class="mdui-menu" id="share_menu">
            <li class="mdui-menu-item">
              <a href="https://service.weibo.com/share/share.php?appkey=&title=Android 14 init进程解析&url=http://longzhiye.top/2024/02/25/2024-02-25/&pic=http://longzhiye.top/images/favicon.png&searchPic=false&style=simple" target="_blank" class="mdui-ripple">分享到 Weibo</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://twitter.com/intent/tweet?text=Android 14 init进程解析&url=http://longzhiye.top/2024/02/25/2024-02-25/&via=龙之叶" target="_blank" class="mdui-ripple">分享到 Twitter</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://www.facebook.com/sharer/sharer.php?u=http://longzhiye.top/2024/02/25/2024-02-25/" target="_blank" class="mdui-ripple">分享到 Facebook</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://plus.google.com/share?url=http://longzhiye.top/2024/02/25/2024-02-25/" target="_blank" class="mdui-ripple">分享到 Google+</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://www.linkedin.com/shareArticle?mini=true&url=http://longzhiye.top/2024/02/25/2024-02-25/&title=Android 14 init进程解析" target="_blank" class="mdui-ripple">分享到 LinkedIn</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://connect.qq.com/widget/shareqq/index.html?site=龙之叶的博客&title=Android 14 init进程解析&pics=http://longzhiye.top/images/favicon.png&url=http://longzhiye.top/2024/02/25/2024-02-25/" target="_blank" class="mdui-ripple">分享到 QQ</a>
            </li>
            <li class="mdui-menu-item">
              <a href="https://telegram.me/share/url?url=http://longzhiye.top/2024/02/25/2024-02-25/&text=Android 14 init进程解析" target="_blank" class="mdui-ripple">分享到 Telegram</a>
            </li>
          </ul>
        
      </div>
    </header>
    <div class="mdui-card-content mdui-typo">
      <h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>当bootloader启动后，启动kernel，kernel启动完后，在用户空间启动init进程，再通过init进程，来读取init.rc中的相关配置，从而来启动其他相关进程以及其他操作。<br>init进程启动主要分为两个阶段：</p>
<p>第一个阶段负责：</p>
<ul>
<li>创建文件系统目录并挂载相关的文件系统</li>
<li>初始化日志输出</li>
<li>启用SELinux安全策略</li>
<li>为第二阶段做准备</li>
</ul>
<p>第二阶段负责：</p>
<ul>
<li>创建进程会话密钥、并初始化属性系统</li>
<li>执行SELinux第二阶段、并恢复一些文件安全上下文</li>
<li>新建epoll、并初始化子进程终止信号处理函数</li>
<li>设置其他系统属性、并开启属性服务</li>
<li>解析init.rc等文件，建立rc文件的action、service，启动其他进程</li>
</ul>
<h4 id="init进程如何被启动？"><a href="#init进程如何被启动？" class="headerlink" title="init进程如何被启动？"></a>init进程如何被启动？</h4><p>init进程是在Kernel启动后，启动的第一个用户空间进程，PID为1<br><strong>kernel-5.10/init/main.c</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> __ref <span class="title function_">kernel_init</span><span class="params">(<span class="type">void</span> *unused)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"> </span><br><span class="line">    kernel_init_freeable();<span class="comment">//进行init进程的一些初始化操作</span></span><br><span class="line">    <span class="comment">/* need to finish all async __init code before freeing the memory */</span></span><br><span class="line">    async_synchronize_full();<span class="comment">//等待所有异步调用执行完成，在释放内存前，必须完成所有的异步 __init 代码</span></span><br><span class="line">    ftrace_free_init_mem();</span><br><span class="line">    jump_label_invalidate_initmem();</span><br><span class="line">    free_initmem();<span class="comment">//释放所有init.*中的内存</span></span><br><span class="line">    mark_readonly();</span><br><span class="line"> </span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Kernel mappings are now finalized - update the userspace page-table</span></span><br><span class="line"><span class="comment">     * to finalize PTI.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    pti_finalize();</span><br><span class="line"> </span><br><span class="line">    system_state = SYSTEM_RUNNING;<span class="comment">//设置系统状态为运行状态</span></span><br><span class="line">    numa_default_policy();<span class="comment">//设定NUMA系统的默认内存访问策略</span></span><br><span class="line"> </span><br><span class="line">    rcu_end_inkernel_boot();</span><br><span class="line"> </span><br><span class="line">    bootprof_log_boot(<span class="string">&quot;Kernel_init_done&quot;</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (ramdisk_execute_command) &#123;<span class="comment">//ramdisk_execute_command的值为“/init”</span></span><br><span class="line">        ret = run_init_process(ramdisk_execute_command);<span class="comment">//运行根目录下的init进程 *****</span></span><br><span class="line">        <span class="keyword">if</span> (!ret)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        pr_err(<span class="string">&quot;Failed to execute %s (error %d)\n&quot;</span>,</span><br><span class="line">               ramdisk_execute_command, ret);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * We try each of these until one succeeds.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * The Bourne shell can be used instead of init if we are</span></span><br><span class="line"><span class="comment">     * trying to recover a really broken machine.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (execute_command) &#123;<span class="comment">//execute_command的值如果有定义就去根目录下找对应的应用程序,然后启动</span></span><br><span class="line">        ret = run_init_process(execute_command);</span><br><span class="line">        <span class="keyword">if</span> (!ret)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        panic(<span class="string">&quot;Requested init %s failed (error %d).&quot;</span>,</span><br><span class="line">              execute_command, ret);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (!try_to_run_init_process(<span class="string">&quot;/sbin/init&quot;</span>) ||</span><br><span class="line">        !try_to_run_init_process(<span class="string">&quot;/etc/init&quot;</span>) ||</span><br><span class="line">        !try_to_run_init_process(<span class="string">&quot;/bin/init&quot;</span>) ||</span><br><span class="line">        !try_to_run_init_process(<span class="string">&quot;/bin/sh&quot;</span>))<span class="comment">//如果ramdisk_execute_command和execute_command定义的应用程序都没有找到，</span></span><br><span class="line">    <span class="comment">//就到根目录下找 /sbin/init，/etc/init，/bin/init,/bin/sh 这四个应用程序进行启动</span></span><br><span class="line"> </span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> </span><br><span class="line">    panic(<span class="string">&quot;No working init found.  Try passing init= option to kernel. &quot;</span></span><br><span class="line">          <span class="string">&quot;See Linux Documentation/admin-guide/init.rst for guidance.&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在/kernel/init/mian.c#kernel_init()方法调用了run_init_process()进行启动init进程</p>
<h3 id="init进程入口"><a href="#init进程入口" class="headerlink" title="init进程入口"></a>init进程入口</h3><p>在Android Q（10.0）之前的init入口函数是init.cpp，从Android Q（10.0）开始init的入口函数是main.cpp，把各个阶段的操作分离开来，是代码更加简洁。<br>进入到main.cpp#main()<br><strong>system/core/init/main.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 1.第一个参数argc表示参数个数，第二个参数是参数列表，也就是具体的参数</span></span><br><span class="line"><span class="comment"> * 2.main函数有四个参数入口，</span></span><br><span class="line"><span class="comment"> *一是参数中有ueventd，进入ueventd_main</span></span><br><span class="line"><span class="comment"> *二是参数中有subcontext，进入InitLogging 和SubcontextMain</span></span><br><span class="line"><span class="comment"> *三是参数中有selinux_setup，进入SetupSelinux</span></span><br><span class="line"><span class="comment"> *四是参数中有second_stage，进入SecondStageMain</span></span><br><span class="line"><span class="comment"> * 3.main的执行顺序如下：</span></span><br><span class="line"><span class="comment">   *  (1)ueventd_main    init进程创建子进程ueventd，</span></span><br><span class="line"><span class="comment">   *      并将创建设备节点文件的工作托付给ueventd，ueventd通过两种方式创建设备节点文件</span></span><br><span class="line"><span class="comment">   *  (2)FirstStageMain  启动第一阶段</span></span><br><span class="line"><span class="comment">   *  (3)SetupSelinux     加载selinux规则，并设置selinux日志,完成SELinux相关工作</span></span><br><span class="line"><span class="comment">   *  (4)SecondStageMain  启动第二阶段</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> </span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> __has_feature(address_sanitizer)</span></span><br><span class="line">    __asan_set_error_report_callback(AsanReportCallback);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    <span class="comment">// Boost prio which will be restored later</span></span><br><span class="line">    setpriority(PRIO_PROCESS, <span class="number">0</span>, <span class="number">-20</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//当argv[0]的内容为ueventd时，strcmp的值为0，ueventd主要是负责设备节点的创建、权限设定等一些列工作</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(basename(argv[<span class="number">0</span>]), <span class="string">&quot;ueventd&quot;</span>)) &#123;</span><br><span class="line">        <span class="keyword">return</span> ueventd_main(argc, argv);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//当传入的参数个数大于1时</span></span><br><span class="line">    <span class="keyword">if</span> (argc &gt; <span class="number">1</span>) &#123;</span><br><span class="line">        <span class="comment">//参数为subcontext，初始化日志系统</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(argv[<span class="number">1</span>], <span class="string">&quot;subcontext&quot;</span>)) &#123;</span><br><span class="line">            android::base::InitLogging(argv, &amp;android::base::KernelLogger);</span><br><span class="line">            <span class="type">const</span> BuiltinFunctionMap&amp; function_map = GetBuiltinFunctionMap();</span><br><span class="line"> </span><br><span class="line">            <span class="keyword">return</span> SubcontextMain(argc, argv, &amp;function_map);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//参数为selinux_setup，启动Selinux安全策略</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(argv[<span class="number">1</span>], <span class="string">&quot;selinux_setup&quot;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> SetupSelinux(argv);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        <span class="comment">//参数为“sencond_stage”，启动init进程第二阶段</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(argv[<span class="number">1</span>], <span class="string">&quot;second_stage&quot;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> SecondStageMain(argc, argv);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//默认启动init进程第一阶段</span></span><br><span class="line">    <span class="keyword">return</span> FirstStageMain(argc, argv);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="ueventd-main"><a href="#ueventd-main" class="headerlink" title="ueventd_main()"></a>ueventd_main()</h3><p>Android根文件系统的镜像中不存在“/dev”目录，该目录是init进程启动后动态创建的。所以，建立Android中设备节点文件需要init进程完成，为此init进程创建子进程ueventd，并将创建设备节点文件的工作托付给ueventd。<br>ueventd通过两种方式创建设备节点文件：<br>第一种方式对应“冷插拔”（Cold Plug），即以预先定义的设备信息为基础，当ueventd启动后，同一创建设备节点文件。这一类设备节点文件也被称为静态节点文件。<br>第二种方式对应“热插拔”（Hot Plug），即在系统运行中，当有设备插入USB端口时，ueventd就会接收到这一事件，为插入的设备动态创建设备节点文件。这一类设备节点文件也被称为动态节点文件。<br>进入ueventd.cpp#ueventd_main()<br><strong>system/core/init/ueventd.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ueventd_main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> &#123;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * init sets the umask to 077 for forked processes. We need to</span></span><br><span class="line"><span class="comment">     * create files with exact permissions, without modification by</span></span><br><span class="line"><span class="comment">     * the umask.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">//设置新建文件的默认值，这个与chmod相反，这里相当于新建文件后的权限为666</span></span><br><span class="line">    umask(<span class="number">000</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//初始化内核日志，位于节点/dev/kmsg，此时logd、logcat进程还没有起来</span></span><br><span class="line">    <span class="comment">//采用kernel的log系统，打开的设备节点/dev/kmsg，那么可通过cat /dev/kmsg来获取内核log</span></span><br><span class="line">    android::base::InitLogging(argv, &amp;android::base::KernelLogger);</span><br><span class="line"> </span><br><span class="line">    LOG(INFO) &lt;&lt; <span class="string">&quot;ueventd started!&quot;</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//注册selinux相关的用于打印log的回调函数</span></span><br><span class="line">    SelinuxSetupKernelLogging();</span><br><span class="line">    SelabelInitialize();</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">unique_ptr</span>&lt;UeventHandler&gt;&gt; uevent_handlers;</span><br><span class="line">    <span class="comment">//解析xml，根据不同SOC厂商获取不同的hardware rc文件</span></span><br><span class="line">    <span class="keyword">auto</span> ueventd_configuration = GetConfiguration();</span><br><span class="line"> </span><br><span class="line">    uevent_handlers.emplace_back(<span class="built_in">std</span>::make_unique&lt;DeviceHandler&gt;(</span><br><span class="line">            <span class="built_in">std</span>::move(ueventd_configuration.dev_permissions),</span><br><span class="line">            <span class="built_in">std</span>::move(ueventd_configuration.sysfs_permissions),</span><br><span class="line">            <span class="built_in">std</span>::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), <span class="literal">true</span>));</span><br><span class="line">    uevent_handlers.emplace_back(<span class="built_in">std</span>::make_unique&lt;FirmwareHandler&gt;(</span><br><span class="line">            <span class="built_in">std</span>::move(ueventd_configuration.firmware_directories),</span><br><span class="line">            <span class="built_in">std</span>::move(ueventd_configuration.external_firmware_handlers)));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//冷启动</span></span><br><span class="line">    <span class="keyword">if</span> (ueventd_configuration.enable_modalias_handling) &#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt; base_paths = &#123;<span class="string">&quot;/odm/lib/modules&quot;</span>, <span class="string">&quot;/vendor/lib/modules&quot;</span>&#125;;</span><br><span class="line">        uevent_handlers.emplace_back(<span class="built_in">std</span>::make_unique&lt;ModaliasHandler&gt;(base_paths));</span><br><span class="line">    &#125;</span><br><span class="line">    UeventListener <span class="title function_">uevent_listener</span><span class="params">(ueventd_configuration.uevent_socket_rcvbuf_size)</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (!android::base::GetBoolProperty(kColdBootDoneProp, <span class="literal">false</span>)) &#123;</span><br><span class="line">        ColdBoot <span class="title function_">cold_boot</span><span class="params">(uevent_listener, uevent_handlers,</span></span><br><span class="line"><span class="params">                           ueventd_configuration.enable_parallel_restorecon)</span>;</span><br><span class="line">        cold_boot.Run();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; uevent_handler : uevent_handlers) &#123;</span><br><span class="line">        uevent_handler-&gt;ColdbootDone();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//忽略子进程终止信号</span></span><br><span class="line">    signal(SIGCHLD, SIG_IGN);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//在最后一次调用waitpid()和为上面的sigchld设置SIG_IGN之间退出的获取和挂起的子级</span></span><br><span class="line">    <span class="keyword">while</span> (waitpid(<span class="number">-1</span>, nullptr, WNOHANG) &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Restore prio before main loop</span></span><br><span class="line">    setpriority(PRIO_PROCESS, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">    <span class="comment">//监听来自驱动的uevent，进行“热插拔”处理</span></span><br><span class="line">    uevent_listener.Poll([&amp;uevent_handlers](<span class="type">const</span> Uevent&amp; uevent) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; uevent_handler : uevent_handlers) &#123;</span><br><span class="line">            uevent_handler-&gt;HandleUevent(uevent);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ListenerAction::kContinue;</span><br><span class="line">    &#125;);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="init进程启动第一阶段first-stage-init-cpp"><a href="#init进程启动第一阶段first-stage-init-cpp" class="headerlink" title="init进程启动第一阶段first_stage_init.cpp"></a>init进程启动第一阶段first_stage_init.cpp</h3><p>主要负责：</p>
<ul>
<li>创建文件系统目录并挂载相关的文件系统</li>
<li>初始化日志输出</li>
<li>启用SELinux安全策略</li>
<li>为第二阶段做准备</li>
</ul>
<p><strong>system/core/init/first_stage_init.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">FirstStageMain</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> &#123;</span><br><span class="line">    <span class="comment">//init crash时重启引导加载程序</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">//这个函数主要作用将各种信号量，如SIGABRT,SIGBUS等的行为设置为SA_RESTART,一旦监听到这些信号即执行重启系统</span></span><br><span class="line">    <span class="keyword">if</span> (REBOOT_BOOTLOADER_ON_PANIC) &#123;</span><br><span class="line">        InstallRebootSignalHandlers();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    boot_clock::time_point start_time = boot_clock::now();</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">pair</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>, <span class="type">int</span>&gt;&gt; errors;</span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> CHECKCALL(x) \</span></span><br><span class="line"><span class="meta">    <span class="keyword">if</span> ((x) != 0) errors.emplace_back(#x <span class="string">&quot; failed&quot;</span>, errno);</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Clear the umask.</span></span><br><span class="line">    <span class="comment">//清空文件权限</span></span><br><span class="line">    umask(<span class="number">0</span>);</span><br><span class="line"> </span><br><span class="line">    CHECKCALL(clearenv());</span><br><span class="line">    CHECKCALL(setenv(<span class="string">&quot;PATH&quot;</span>, _PATH_DEFPATH, <span class="number">1</span>));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//在RAM内存上获取基本的文件系统，剩余的被rc文件所用</span></span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;tmpfs&quot;</span>, <span class="string">&quot;/dev&quot;</span>, <span class="string">&quot;tmpfs&quot;</span>, MS_NOSUID, <span class="string">&quot;mode=0755&quot;</span>));</span><br><span class="line">    CHECKCALL(mkdir(<span class="string">&quot;/dev/pts&quot;</span>, <span class="number">0755</span>));</span><br><span class="line">    CHECKCALL(mkdir(<span class="string">&quot;/dev/socket&quot;</span>, <span class="number">0755</span>));</span><br><span class="line">    CHECKCALL(mkdir(<span class="string">&quot;/dev/dm-user&quot;</span>, <span class="number">0755</span>));</span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;devpts&quot;</span>, <span class="string">&quot;/dev/pts&quot;</span>, <span class="string">&quot;devpts&quot;</span>, <span class="number">0</span>, <span class="literal">NULL</span>));</span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> MAKE_STR(x) __STRING(x)</span></span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;proc&quot;</span>, <span class="string">&quot;/proc&quot;</span>, <span class="string">&quot;proc&quot;</span>, <span class="number">0</span>, <span class="string">&quot;hidepid=2,gid=&quot;</span> MAKE_STR(AID_READPROC)));</span><br><span class="line">    <span class="meta">#<span class="keyword">undef</span> MAKE_STR</span></span><br><span class="line">    <span class="comment">//非特权应用不能使用Android cmdline</span></span><br><span class="line">    CHECKCALL(chmod(<span class="string">&quot;/proc/cmdline&quot;</span>, <span class="number">0440</span>));</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> cmdline;</span><br><span class="line">    android::base::ReadFileToString(<span class="string">&quot;/proc/cmdline&quot;</span>, &amp;cmdline);</span><br><span class="line">    <span class="comment">// Don&#x27;t expose the raw bootconfig to unprivileged processes.</span></span><br><span class="line">    chmod(<span class="string">&quot;/proc/bootconfig&quot;</span>, <span class="number">0440</span>);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> bootconfig;</span><br><span class="line">    android::base::ReadFileToString(<span class="string">&quot;/proc/bootconfig&quot;</span>, &amp;bootconfig);</span><br><span class="line">    <span class="type">gid_t</span> groups[] = &#123;AID_READPROC&#125;;</span><br><span class="line">    CHECKCALL(setgroups(arraysize(groups), groups));</span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;sysfs&quot;</span>, <span class="string">&quot;/sys&quot;</span>, <span class="string">&quot;sysfs&quot;</span>, <span class="number">0</span>, <span class="literal">NULL</span>));</span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;selinuxfs&quot;</span>, <span class="string">&quot;/sys/fs/selinux&quot;</span>, <span class="string">&quot;selinuxfs&quot;</span>, <span class="number">0</span>, <span class="literal">NULL</span>));</span><br><span class="line"> </span><br><span class="line">    CHECKCALL(mknod(<span class="string">&quot;/dev/kmsg&quot;</span>, S_IFCHR | <span class="number">0600</span>, makedev(<span class="number">1</span>, <span class="number">11</span>)));</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> <span class="title function_">constexpr</span> <span class="params">(WORLD_WRITABLE_KMSG)</span> &#123;</span><br><span class="line">        CHECKCALL(mknod(<span class="string">&quot;/dev/kmsg_debug&quot;</span>, S_IFCHR | <span class="number">0622</span>, makedev(<span class="number">1</span>, <span class="number">11</span>)));</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    CHECKCALL(mknod(<span class="string">&quot;/dev/random&quot;</span>, S_IFCHR | <span class="number">0666</span>, makedev(<span class="number">1</span>, <span class="number">8</span>)));</span><br><span class="line">    CHECKCALL(mknod(<span class="string">&quot;/dev/urandom&quot;</span>, S_IFCHR | <span class="number">0666</span>, makedev(<span class="number">1</span>, <span class="number">9</span>)));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//这对于日志包装器是必需的，它在ueventd运行之前被调用</span></span><br><span class="line">    CHECKCALL(mknod(<span class="string">&quot;/dev/ptmx&quot;</span>, S_IFCHR | <span class="number">0666</span>, makedev(<span class="number">5</span>, <span class="number">2</span>)));</span><br><span class="line">    CHECKCALL(mknod(<span class="string">&quot;/dev/null&quot;</span>, S_IFCHR | <span class="number">0666</span>, makedev(<span class="number">1</span>, <span class="number">3</span>)));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//在第一阶段挂在tmpfs、mnt/vendor、mount/product分区。其他的分区不需要在第一阶段加载，</span></span><br><span class="line">    <span class="comment">//只需要在第二阶段通过rc文件解析来加载</span></span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;tmpfs&quot;</span>, <span class="string">&quot;/mnt&quot;</span>, <span class="string">&quot;tmpfs&quot;</span>, MS_NOEXEC | MS_NOSUID | MS_NODEV,</span><br><span class="line">        <span class="string">&quot;mode=0755,uid=0,gid=1000&quot;</span>));</span><br><span class="line">    <span class="comment">//创建可供读写的vendor目录</span></span><br><span class="line">    CHECKCALL(mkdir(<span class="string">&quot;/mnt/vendor&quot;</span>, <span class="number">0755</span>));</span><br><span class="line"> </span><br><span class="line">    CHECKCALL(mkdir(<span class="string">&quot;/mnt/product&quot;</span>, <span class="number">0755</span>));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// 挂载APEX，这在Android 10.0中特殊引入，用来解决碎片化问题，类似一种组件方式，对Treble的增强，</span></span><br><span class="line">    <span class="comment">// 不写谷歌特殊更新不需要完整升级整个系统版本，只需要像升级APK一样，进行APEX组件升级</span></span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;tmpfs&quot;</span>, <span class="string">&quot;/debug_ramdisk&quot;</span>, <span class="string">&quot;tmpfs&quot;</span>, MS_NOEXEC | MS_NOSUID | MS_NODEV,</span><br><span class="line">        <span class="string">&quot;mode=0755,uid=0,gid=0&quot;</span>));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// /second_stage_resources is used to preserve files from first to second</span></span><br><span class="line">    <span class="comment">// stage init</span></span><br><span class="line">    CHECKCALL(mount(<span class="string">&quot;tmpfs&quot;</span>, kSecondStageRes, <span class="string">&quot;tmpfs&quot;</span>, MS_NOEXEC | MS_NOSUID | MS_NODEV,</span><br><span class="line">    <span class="string">&quot;mode=0755,uid=0,gid=0&quot;</span>))</span><br><span class="line">    <span class="meta">#<span class="keyword">undef</span> CHECKCALL</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">//把标准输入、标准输出和标准错误重定向到空设备文件“/dev/null”</span></span><br><span class="line">    SetStdioToDevNull(argv);</span><br><span class="line">    <span class="comment">// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually</span></span><br><span class="line"><span class="comment">// talk to the outside world...</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> MTK_LOG_DISABLERATELIMIT</span></span><br><span class="line"><span class="keyword">if</span> (cmdline.find(<span class="string">&quot;init.mtklogdrl=1&quot;</span>) != <span class="built_in">std</span>::<span class="built_in">string</span>::npos)</span><br><span class="line">SetMTKLOGDISABLERATELIMIT();</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">SetMTKLOGDISABLERATELIMIT();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// MTK_LOG_DISABLERATELIMIT</span></span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT())</span><br><span class="line">InitKernelLogging_split(argv);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">InitKernelLogging(argv);</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="comment">//在/dev目录下挂载好tmpfs以及kmsg</span></span><br><span class="line"><span class="comment">//这样就可以初始化/kernel Log系统，供用户打印log</span></span><br><span class="line">InitKernelLogging(argv);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line">......</span><br><span class="line"> </span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">初始化一些必须的分区</span></span><br><span class="line"><span class="comment">主要作用是去解析/proc/device-tree/firmware/android/fstab</span></span><br><span class="line"><span class="comment">然后得到“/system”，“/vendor”，“/odm”三个目录的挂载信息</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">if</span> (!DoFirstStageMount(!created_devices)) &#123;</span><br><span class="line">LOG(FATAL) &lt;&lt; <span class="string">&quot;Failed to mount required partitions early ...&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">new_root_info</span>;</span></span><br><span class="line"><span class="keyword">if</span> (stat(<span class="string">&quot;/&quot;</span>, &amp;new_root_info) != <span class="number">0</span>) &#123;</span><br><span class="line">PLOG(ERROR) &lt;&lt; <span class="string">&quot;Could not stat(\&quot;/\&quot;), not freeing ramdisk&quot;</span>;</span><br><span class="line">old_root_dir.reset();</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (old_root_dir &amp;&amp; old_root_info.st_dev != new_root_info.st_dev) &#123;</span><br><span class="line">FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">SetInitAvbVersionInRecovery();</span><br><span class="line"> </span><br><span class="line">setenv(kEnvFirstStageStartedAt, <span class="built_in">std</span>::to_string(start_time.time_since_epoch().count()).c_str(),</span><br><span class="line"><span class="number">1</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//启动init进程，传入参数selinux_steup</span></span><br><span class="line"><span class="comment">//执行命令：/system/bin/init selinux_setup</span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* path = <span class="string">&quot;/system/bin/init&quot;</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* args[] = &#123;path, <span class="string">&quot;selinux_setup&quot;</span>, nullptr&#125;;</span><br><span class="line"><span class="keyword">auto</span> fd = open(<span class="string">&quot;/dev/kmsg&quot;</span>, O_WRONLY | O_CLOEXEC);</span><br><span class="line">dup2(fd, STDOUT_FILENO);</span><br><span class="line">dup2(fd, STDERR_FILENO);</span><br><span class="line">close(fd);</span><br><span class="line">execv(path, const_cast&lt;<span class="type">char</span>**&gt;(args));</span><br><span class="line"> </span><br><span class="line"><span class="comment">// execv() only returns if an error happened, in which case we</span></span><br><span class="line"><span class="comment">// panic and never fall through this conditional.</span></span><br><span class="line">PLOG(FATAL) &lt;&lt; <span class="string">&quot;execv(\&quot;&quot;</span> &lt;&lt; path &lt;&lt; <span class="string">&quot;\&quot;) failed&quot;</span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="加载SELinux规则"><a href="#加载SELinux规则" class="headerlink" title="加载SELinux规则"></a>加载SELinux规则</h3><p>SELinux是「Security-Enhanced Linux」的简称，是美国国家安全局「NSA=The National Security Agency」<br>和SCC（Secure Computing Corporation）开发的 Linux的一个扩张强制访问控制安全模块。在这种访问控制体系的限制下，进程只能访问那些在他的任务中所需要文件。<br>SElinux有两种工作模式：</p>
<ol>
<li>permissive，所有的操作都被允许（即没有MAC），但是如果违法权限的话，会记录日志，一般eng模式用</li>
<li>enforcing，所有操作都会进行权限检查，一般user和user-debug模式用</li>
</ol>
<p>不管是security_setenforce还是security_getenforce都是去操作/sys/fs/selinux/enforce文件，<strong>0表示permissive 1表示enforcing</strong><br>SetupSelinux：初始化selinux，加载SElinux规则，配置SWLinux相关log输出，并启动第二阶段<br><strong>system/core/init/selinux.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*此函数初始化selinux，然后执行init以在init selinux中运行*/</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">SetupSelinux</span><span class="params">(<span class="type">char</span>** argv)</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> JOURNEY_FEATURE_ROOT_MODE</span></span><br><span class="line">    initJourneyRootMode();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    SetStdioToDevNull(argv);</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> MTK_LOG_DISABLERATELIMIT</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">string</span> cmdline;</span><br><span class="line">        android::base::ReadFileToString(<span class="string">&quot;/proc/cmdline&quot;</span>, &amp;cmdline);</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">if</span> (cmdline.find(<span class="string">&quot;init.mtklogdebuggable=1&quot;</span>) != <span class="built_in">std</span>::<span class="built_in">string</span>::npos)</span><br><span class="line">            SetMTKLOGDISABLERATELIMIT();</span><br><span class="line">    &#125;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    SetMTKLOGDISABLERATELIMIT();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// MTK_LOG_DISABLERATELIMIT</span></span></span><br><span class="line">    <span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT())</span><br><span class="line">        InitKernelLogging_split(argv);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        InitKernelLogging(argv);</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="comment">//初始化Kernel日志</span></span><br><span class="line">    InitKernelLogging(argv);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">//Debug版本init crash时重启引导加载程序</span></span><br><span class="line">    <span class="keyword">if</span> (REBOOT_BOOTLOADER_ON_PANIC) &#123;</span><br><span class="line">        InstallRebootSignalHandlers();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    boot_clock::time_point start_time = boot_clock::now();</span><br><span class="line"> </span><br><span class="line">    MountMissingSystemPartitions();</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line">    <span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT())</span><br><span class="line">        SelinuxSetupKernelLogging_split();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        SelinuxSetupKernelLogging();</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="comment">//注册回调，用来设置需要写入kmsg的selinux日志</span></span><br><span class="line">    SelinuxSetupKernelLogging();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line">    LOG(INFO) &lt;&lt; <span class="string">&quot;Opening SELinux policy&quot;</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Read the policy before potentially killing snapuserd.</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> policy;</span><br><span class="line">    ReadPolicy(&amp;policy);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">auto</span> snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();</span><br><span class="line">    <span class="keyword">if</span> (snapuserd_helper) &#123;</span><br><span class="line">        <span class="comment">// Kill the old snapused to avoid audit messages. After this we cannot</span></span><br><span class="line">        <span class="comment">// read from /system (or other dynamic partitions) until we call</span></span><br><span class="line">        <span class="comment">// FinishTransition().</span></span><br><span class="line">        snapuserd_helper-&gt;StartTransition();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    LoadSelinuxPolicy(policy);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (snapuserd_helper) &#123;</span><br><span class="line">        <span class="comment">// Before enforcing, finish the pending snapuserd transition.</span></span><br><span class="line">        snapuserd_helper-&gt;FinishTransition();</span><br><span class="line">        snapuserd_helper = nullptr;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//加载SElinux规则</span></span><br><span class="line">    SelinuxSetEnforcement();</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// We&#x27;re in the kernel domain and want to transition to the init domain.  File systems that</span></span><br><span class="line">    <span class="comment">// store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,</span></span><br><span class="line">    <span class="comment">// but other file systems do.  In particular, this is needed for ramdisks such as the</span></span><br><span class="line">    <span class="comment">// recovery image for A/B devices.</span></span><br><span class="line">    <span class="keyword">if</span> (selinux_android_restorecon(<span class="string">&quot;/system/bin/init&quot;</span>, <span class="number">0</span>) == <span class="number">-1</span>) &#123;</span><br><span class="line">        PLOG(FATAL) &lt;&lt; <span class="string">&quot;restorecon failed of /system/bin/init failed&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    setenv(kEnvSelinuxStartedAt, <span class="built_in">std</span>::to_string(start_time.time_since_epoch().count()).c_str(), <span class="number">1</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//准备启动init进程，传入参数second_stage，进入到第二阶段</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* path = <span class="string">&quot;/system/bin/init&quot;</span>;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* args[] = &#123;path, <span class="string">&quot;second_stage&quot;</span>, nullptr&#125;;</span><br><span class="line">    execv(path, const_cast&lt;<span class="type">char</span>**&gt;(args));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// execv() only returns if an error happened, in which case we</span></span><br><span class="line">    <span class="comment">// panic and never return from this function.</span></span><br><span class="line">    PLOG(FATAL) &lt;&lt; <span class="string">&quot;execv(\&quot;&quot;</span> &lt;&lt; path &lt;&lt; <span class="string">&quot;\&quot;) failed&quot;</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>SelinuxSetEnforcement()：加载SeLinux规则<br><strong>system/core/init/selinux.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">SelinuxSetEnforcement</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">//获取当前Kernel的工作模式</span></span><br><span class="line">    <span class="type">bool</span> kernel_enforcing = (security_getenforce() == <span class="number">1</span>);</span><br><span class="line">    <span class="comment">//获取工作模式的配置</span></span><br><span class="line">    <span class="type">bool</span> is_enforcing = IsEnforcing();</span><br><span class="line">    <span class="comment">//如果当前的工作模式与配置的不同，就将当前的工作模式改掉</span></span><br><span class="line">    <span class="keyword">if</span> (kernel_enforcing != is_enforcing) &#123;</span><br><span class="line">        <span class="keyword">if</span> (security_setenforce(is_enforcing)) &#123;</span><br><span class="line">            PLOG(FATAL) &lt;&lt; <span class="string">&quot;security_setenforce(&quot;</span> &lt;&lt; (is_enforcing ? <span class="string">&quot;true&quot;</span> : <span class="string">&quot;false&quot;</span>)</span><br><span class="line">                &lt;&lt; <span class="string">&quot;) failed&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">auto</span> result = WriteFile(<span class="string">&quot;/sys/fs/selinux/checkreqprot&quot;</span>, <span class="string">&quot;0&quot;</span>); !result.ok()) &#123;</span><br><span class="line">        LOG(FATAL) &lt;&lt; <span class="string">&quot;Unable to write to /sys/fs/selinux/checkreqprot: &quot;</span> &lt;&lt; result.error();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="init进程启动第二阶段"><a href="#init进程启动第二阶段" class="headerlink" title="init进程启动第二阶段"></a>init进程启动第二阶段</h3><p>主要负责：</p>
<ul>
<li>创建进程会话密钥，并初始化属性系统</li>
<li>执行SELinux第二阶段，并恢复一些文件安全上下文</li>
<li>新建epoll，并初始化子进程终止信号处理函数</li>
<li>设置其他系统属性，并开启属性服务</li>
<li>解析init.rc等文件，建立rc文件的action、service，启动其他进程</li>
</ul>
<p><img src="/images/20240225/20240225001.png"></p>
<p><strong>system/core/init/init.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">SecondStageMain</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span> &#123;</span><br><span class="line">    <span class="meta">#<span class="keyword">ifdef</span> JOURNEY_FEATURE_ROOT_MODE</span></span><br><span class="line">    initJourneyRootMode();</span><br><span class="line">    <span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">*init crash时重启引导加载程序</span></span><br><span class="line"><span class="comment">*这个函数主要作用将各种信号量，如SIGABRT,SIGBUS等的行为设置为SA_RESTART,一旦监听到这些信号即执行重启系统</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">    <span class="keyword">if</span> (REBOOT_BOOTLOADER_ON_PANIC) &#123;</span><br><span class="line">        InstallRebootSignalHandlers();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    boot_clock::time_point start_time = boot_clock::now();</span><br><span class="line"> </span><br><span class="line">    trigger_shutdown = [](<span class="type">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; command) &#123; shutdown_state.TriggerShutdown(command); &#125;;</span><br><span class="line">    <span class="comment">//把标准输入、标准输出和标准错误重定向到空设备文件“/dev/null&quot;</span></span><br><span class="line">    SetStdioToDevNull(argv);</span><br><span class="line">    <span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line">    <span class="meta">#<span class="keyword">ifndef</span> MTK_LOG_DISABLERATELIMIT</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">string</span> cmdline;</span><br><span class="line">        android::base::ReadFileToString(<span class="string">&quot;/proc/cmdline&quot;</span>, &amp;cmdline);</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">if</span> (cmdline.find(<span class="string">&quot;init.mtklogdrl=1&quot;</span>) != <span class="built_in">std</span>::<span class="built_in">string</span>::npos)</span><br><span class="line">            SetMTKLOGDISABLERATELIMIT();</span><br><span class="line"> </span><br><span class="line">        <span class="type">const</span> <span class="type">char</span>* force_debuggable_env = getenv(<span class="string">&quot;INIT_FORCE_DEBUGGABLE&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (force_debuggable_env &amp;&amp; AvbHandle::IsDeviceUnlocked()) &#123;</span><br><span class="line">            SetMTKLOGDISABLERATELIMIT();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    SetMTKLOGDISABLERATELIMIT();</span><br><span class="line">    <span class="meta">#<span class="keyword">endif</span> <span class="comment">// MTK_LOG_DISABLERATELIMIT</span></span></span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT())</span><br><span class="line">        InitKernelLogging_split(argv);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        InitKernelLogging(argv);</span><br><span class="line">    <span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="comment">//在/dev目录下挂载好tmpfs以及kmsg</span></span><br><span class="line">    <span class="comment">//这样就可以初始化/kernel log系统，供用户打印log</span></span><br><span class="line">    InitKernelLogging(argv);</span><br><span class="line">    <span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    LOG(INFO) &lt;&lt; <span class="string">&quot;init second stage started!&quot;</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Update $PATH in the case the second stage init is newer than first stage init, where it is</span></span><br><span class="line">    <span class="comment">// first set.</span></span><br><span class="line">    <span class="keyword">if</span> (setenv(<span class="string">&quot;PATH&quot;</span>, _PATH_DEFPATH, <span class="number">1</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">        PLOG(FATAL) &lt;&lt; <span class="string">&quot;Could not set $PATH to &#x27;&quot;</span> &lt;&lt; _PATH_DEFPATH &lt;&lt; <span class="string">&quot;&#x27; in second stage&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Init should not crash because of a dependence on any other process, therefore we ignore</span></span><br><span class="line">    <span class="comment">// SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN</span></span><br><span class="line">    <span class="comment">// is inherited across exec, but custom signal handlers are not.  Since we do not want to</span></span><br><span class="line">    <span class="comment">// ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">action</span> =</span> &#123;.sa_flags = SA_RESTART&#125;;</span><br><span class="line">        action.sa_handler = [](<span class="type">int</span>) &#123;&#125;;</span><br><span class="line">        sigaction(SIGPIPE, &amp;action, nullptr);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Set init and its forked children&#x27;s oom_adj.</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">auto</span> result =</span><br><span class="line">        WriteFile(<span class="string">&quot;/proc/1/oom_score_adj&quot;</span>, StringPrintf(<span class="string">&quot;%d&quot;</span>, DEFAULT_OOM_SCORE_ADJUST));</span><br><span class="line">        !result.ok()) &#123;</span><br><span class="line">        LOG(ERROR) &lt;&lt; <span class="string">&quot;Unable to write &quot;</span> &lt;&lt; DEFAULT_OOM_SCORE_ADJUST</span><br><span class="line">            &lt;&lt; <span class="string">&quot; to /proc/1/oom_score_adj: &quot;</span> &lt;&lt; result.error();</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Set up a session keyring that all processes will have access to. It</span></span><br><span class="line">    <span class="comment">// will hold things like FBE encryption keys. No process should override</span></span><br><span class="line">    <span class="comment">// its session keyring.</span></span><br><span class="line">    <span class="comment">//01.创建进程会话密钥并初始化属性系统</span></span><br><span class="line">    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, <span class="number">1</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Indicate that booting is in progress to background fw loaders, etc.</span></span><br><span class="line">    <span class="comment">//创建/dev/.booting文件，就是个标记，表示booting进行中</span></span><br><span class="line">    close(open(<span class="string">&quot;/dev/.booting&quot;</span>, O_WRONLY | O_CREAT | O_CLOEXEC, <span class="number">0000</span>));</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// See if need to load debug props to allow adb root, when the device is unlocked.</span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* force_debuggable_env = getenv(<span class="string">&quot;INIT_FORCE_DEBUGGABLE&quot;</span>);</span><br><span class="line"><span class="type">bool</span> load_debug_prop = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">if</span> (force_debuggable_env &amp;&amp; AvbHandle::IsDeviceUnlocked()) &#123;</span><br><span class="line">load_debug_prop = <span class="string">&quot;true&quot;</span>s == force_debuggable_env;</span><br><span class="line">&#125;</span><br><span class="line">unsetenv(<span class="string">&quot;INIT_FORCE_DEBUGGABLE&quot;</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Umount the debug ramdisk so property service doesn&#x27;t read .prop files from there, when it</span></span><br><span class="line"><span class="comment">// is not meant to.</span></span><br><span class="line"><span class="keyword">if</span> (!load_debug_prop) &#123;</span><br><span class="line">UmountDebugRamdisk();</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//初始化属性系统，并从指定文件读取属性</span></span><br><span class="line">PropertyInit();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Umount second stage resources after property service has read the .prop files.</span></span><br><span class="line">UmountSecondStageRes();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Umount the debug ramdisk after property service has read the .prop files when it means to.</span></span><br><span class="line"><span class="keyword">if</span> (load_debug_prop) &#123;</span><br><span class="line">UmountDebugRamdisk();</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Mount extra filesystems required during second stage init</span></span><br><span class="line">MountExtraFilesystems();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Now set up SELinux for second stage.</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line"><span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT())</span><br><span class="line">SelinuxSetupKernelLogging_split();</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">SelinuxSetupKernelLogging();</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">SelinuxSetupKernelLogging();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">SelabelInitialize();</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">02.进行SELinux第二阶段并恢复一些文件安全上下文</span></span><br><span class="line"><span class="comment">恢复相关文件的安全上下文，因为这些文件是在SELinux安全机制初始化前创建的</span></span><br><span class="line"><span class="comment">所以需要重新恢复上下文</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">SelinuxRestoreContext();</span><br><span class="line"> </span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">03.新建epoll并初始化子进程终止信号处理函数</span></span><br><span class="line"><span class="comment">创建epoll实例，并返回epoll的文件描述</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">Epoll epoll;</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">auto</span> result = epoll.Open(); !result.ok()) &#123;</span><br><span class="line">PLOG(FATAL) &lt;&lt; result.error();</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> G1122717</span></span><br><span class="line"><span class="comment">// Watch properties with specific meanings to init.</span></span><br><span class="line">LOG(INFO) &lt;&lt; <span class="string">&quot;Apply watching properties with specific meanings to init.&quot;</span>;</span><br><span class="line">ActionManager::GetInstance().StartWatchingProperty(<span class="string">&quot;sys.powerctl&quot;</span>);</span><br><span class="line">ActionManager::GetInstance().StartWatchingProperty(<span class="string">&quot;ro.persistent_properties.ready&quot;</span>);</span><br><span class="line">ActionManager::GetInstance().StartWatchingProperty(kColdBootDoneProp);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">主要是创建handler处理子进程终止信号，注册一个signal到epoll进行监听</span></span><br><span class="line"><span class="comment">进行子继承处理</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">InstallSignalFdHandler(&amp;epoll);</span><br><span class="line">InstallInitNotifier(&amp;epoll);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//04.设置其他系统属性并开启系统属性服务</span></span><br><span class="line">StartPropertyService(&amp;property_fd);</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(MTK_LOG) &amp;&amp; defined(MTK_COMMAND_WDOG)</span></span><br><span class="line">ActionManager::GetInstance().StartCommandWDOG();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// Make the time that init stages started available for bootstat to log.</span></span><br><span class="line">RecordStageBoottimes(start_time);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Set libavb version for Framework-only OTA match in Treble build.</span></span><br><span class="line"><span class="keyword">if</span> (<span class="type">const</span> <span class="type">char</span>* avb_version = getenv(<span class="string">&quot;INIT_AVB_VERSION&quot;</span>); avb_version != nullptr) &#123;</span><br><span class="line">SetProperty(<span class="string">&quot;ro.boot.avb_version&quot;</span>, avb_version);</span><br><span class="line">&#125;</span><br><span class="line">unsetenv(<span class="string">&quot;INIT_AVB_VERSION&quot;</span>);</span><br><span class="line"> </span><br><span class="line">fs_mgr_vendor_overlay_mount_all();</span><br><span class="line">export_oem_lock_status();</span><br><span class="line">MountHandler <span class="title function_">mount_handler</span><span class="params">(&amp;epoll)</span>;</span><br><span class="line">SetUsbController();</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> JOURNEY_FEATURE_SECURE</span></span><br><span class="line">CheckJourneySecureMode();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> </span><br><span class="line"><span class="type">const</span> BuiltinFunctionMap&amp; function_map = GetBuiltinFunctionMap();</span><br><span class="line">Action::set_function_map(&amp;function_map);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (!SetupMountNamespaces()) &#123;</span><br><span class="line">PLOG(FATAL) &lt;&lt; <span class="string">&quot;SetupMountNamespaces failed&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//初始化文件上下文</span></span><br><span class="line">InitializeSubcontext();</span><br><span class="line"> </span><br><span class="line">ActionManager&amp; am = ActionManager::GetInstance();</span><br><span class="line">ServiceList&amp; sm = ServiceList::GetInstance();</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">05.解析init.rc等文件，建立rc文件的action、service，启动其他进程</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">LoadBootScripts(am, sm);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Turning this on and letting the INFO logging be discarded adds 0.2s to</span></span><br><span class="line"><span class="comment">// Nexus 9 boot time, so it&#x27;s disabled by default.</span></span><br><span class="line"><span class="keyword">if</span> (<span class="literal">false</span>) DumpState();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Make the GSI status available before scripts start running.</span></span><br><span class="line"><span class="comment">//当GSI脚本running时，确保GSI状态可用</span></span><br><span class="line"><span class="keyword">auto</span> is_running = android::gsi::IsGsiRunning() ? <span class="string">&quot;1&quot;</span> : <span class="string">&quot;0&quot;</span>;</span><br><span class="line">SetProperty(gsi::kGsiBootedProp, is_running);</span><br><span class="line"><span class="keyword">auto</span> is_installed = android::gsi::IsGsiInstalled() ? <span class="string">&quot;1&quot;</span> : <span class="string">&quot;0&quot;</span>;</span><br><span class="line">SetProperty(gsi::kGsiInstalledProp, is_installed);</span><br><span class="line"> </span><br><span class="line">am.QueueBuiltinAction(SetupCgroupsAction, <span class="string">&quot;SetupCgroups&quot;</span>);</span><br><span class="line">am.QueueBuiltinAction(SetKptrRestrictAction, <span class="string">&quot;SetKptrRestrict&quot;</span>);</span><br><span class="line">am.QueueBuiltinAction(TestPerfEventSelinuxAction, <span class="string">&quot;TestPerfEventSelinux&quot;</span>);</span><br><span class="line"><span class="comment">//执行rc文件中触发器为 on early-init的语句</span></span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;early-init&quot;</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...</span></span><br><span class="line"><span class="comment">//等冷插拔设备初始化完成</span></span><br><span class="line">am.QueueBuiltinAction(wait_for_coldboot_done_action, <span class="string">&quot;wait_for_coldboot_done&quot;</span>);</span><br><span class="line"><span class="comment">// ... so that we can start queuing up actions that require stuff from /dev.</span></span><br><span class="line">am.QueueBuiltinAction(SetMmapRndBitsAction, <span class="string">&quot;SetMmapRndBits&quot;</span>);</span><br><span class="line"><span class="comment">//设备组合键的初始化操作</span></span><br><span class="line">Keychords keychords;</span><br><span class="line">am.QueueBuiltinAction(</span><br><span class="line">[&amp;epoll, &amp;keychords](<span class="type">const</span> BuiltinArguments&amp; args) -&gt; Result&lt;<span class="type">void</span>&gt; &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">const</span> <span class="keyword">auto</span>&amp; svc : ServiceList::GetInstance()) &#123;</span><br><span class="line">keychords.Register(svc-&gt;keycodes());</span><br><span class="line">&#125;</span><br><span class="line">keychords.Start(&amp;epoll, HandleKeychord);</span><br><span class="line"><span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="string">&quot;KeychordInit&quot;</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Trigger all the boot actions to get us started.</span></span><br><span class="line"><span class="comment">//执行rc文件中触发器为on init的语句</span></span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;init&quot;</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Don&#x27;t mount filesystems or start core system services in charger mode.</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">当设备处于充电模式时，不需要mount文件系统或者启动系统服务</span></span><br><span class="line"><span class="comment">充电模式下，将charger加入执行队列，否则把late-init加入执行队列</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="built_in">std</span>::<span class="built_in">string</span> bootmode = GetProperty(<span class="string">&quot;ro.bootmode&quot;</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (bootmode == <span class="string">&quot;charger&quot;</span>) &#123;</span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;charger&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;late-init&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Run all property triggers based on current state of the properties.</span></span><br><span class="line"><span class="comment">//基于属性当前状态，运行所有的属性触发器</span></span><br><span class="line">am.QueueBuiltinAction(queue_property_triggers_action, <span class="string">&quot;queue_property_triggers&quot;</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Restore prio before main loop</span></span><br><span class="line">setpriority(PRIO_PROCESS, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line"><span class="comment">// By default, sleep until something happens.</span></span><br><span class="line"><span class="keyword">auto</span> epoll_timeout = <span class="built_in">std</span>::optional&lt;<span class="built_in">std</span>::chrono::milliseconds&gt;&#123;&#125;;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">auto</span> shutdown_command = shutdown_state.CheckShutdown();</span><br><span class="line"><span class="keyword">if</span> (shutdown_command) &#123;</span><br><span class="line">LOG(INFO) &lt;&lt; <span class="string">&quot;Got shutdown_command &#x27;&quot;</span> &lt;&lt; *shutdown_command</span><br><span class="line">&lt;&lt; <span class="string">&quot;&#x27; Calling HandlePowerctlMessage()&quot;</span>;</span><br><span class="line">HandlePowerctlMessage(*shutdown_command);</span><br><span class="line">shutdown_state.set_do_shutdown(<span class="literal">false</span>);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//依次执行每个action中携带command对应的执行函数</span></span><br><span class="line"><span class="keyword">if</span> (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) &#123;</span><br><span class="line">am.ExecuteOneCommand();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (!IsShuttingDown()) &#123;</span><br><span class="line"><span class="keyword">auto</span> next_process_action_time = HandleProcessActions();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// If there&#x27;s a process that needs restarting, wake up in time for that.</span></span><br><span class="line"><span class="keyword">if</span> (next_process_action_time) &#123;</span><br><span class="line">epoll_timeout = <span class="built_in">std</span>::chrono::<span class="built_in">ceil</span>&lt;<span class="built_in">std</span>::chrono::milliseconds&gt;(</span><br><span class="line">*next_process_action_time - boot_clock::now());</span><br><span class="line"><span class="keyword">if</span> (*epoll_timeout &lt; <span class="number">0</span>ms) epoll_timeout = <span class="number">0</span>ms;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) &#123;</span><br><span class="line"><span class="comment">// If there&#x27;s more work to do, wake up again immediately.</span></span><br><span class="line"><span class="keyword">if</span> (am.HasMoreCommands()) epoll_timeout = <span class="number">0</span>ms;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> MTK_LOG</span></span><br><span class="line"><span class="type">int</span> log_ms = _LogReap();<span class="comment">//PropSetLogReap();</span></span><br><span class="line"><span class="keyword">if</span> (log_ms &gt; <span class="number">-1</span> &amp;&amp; (!epoll_timeout || epoll_timeout-&gt;count() &gt; log_ms))</span><br><span class="line">epoll_timeout = <span class="built_in">std</span>::chrono::milliseconds(log_ms);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT()) &#123;</span><br><span class="line"><span class="keyword">if</span> (!Getwhilepiggybacketed(<span class="number">1</span>) &amp;&amp; Getwhileepduration(<span class="number">1</span>) &gt; <span class="number">1999</span>)</span><br><span class="line">LOG(INFO) &lt;&lt; <span class="string">&quot;Lastest epoll wait tooks &quot;</span> &lt;&lt; Getwhileepduration(<span class="number">1</span>) &lt;&lt; <span class="string">&quot;ms&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">android::base::Timer t;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">auto</span> pending_functions = epoll.Wait(epoll_timeout);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (GetMTKLOGDISABLERATELIMIT()) &#123;</span><br><span class="line"><span class="type">uint64_t</span> duration = t.duration().count();</span><br><span class="line"><span class="type">uint64_t</span> nowms = <span class="built_in">std</span>::chrono::duration_cast&lt;<span class="built_in">std</span>::chrono::milliseconds&gt;(boot_clock::now().time_since_epoch()).count();</span><br><span class="line">Setwhiletime(<span class="number">1</span>, duration, nowms);</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="keyword">auto</span> pending_functions = epoll.Wait(epoll_timeout);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="keyword">if</span> (!pending_functions.ok()) &#123;</span><br><span class="line">LOG(ERROR) &lt;&lt; pending_functions.error();</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (!pending_functions-&gt;empty()) &#123;</span><br><span class="line"><span class="comment">// We always reap children before responding to the other pending functions. This is to</span></span><br><span class="line"><span class="comment">// prevent a race where other daemons see that a service has exited and ask init to</span></span><br><span class="line"><span class="comment">// start it again via ctl.start before init has reaped it.</span></span><br><span class="line">ReapAnyOutstandingChildren();</span><br><span class="line"><span class="keyword">for</span> (<span class="type">const</span> <span class="keyword">auto</span>&amp; function : *pending_functions) &#123;</span><br><span class="line">(*function)();</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (!IsShuttingDown()) &#123;</span><br><span class="line">HandleControlMessages();</span><br><span class="line">SetUsbController();</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="信号处理"><a href="#信号处理" class="headerlink" title="信号处理"></a>信号处理</h3><p>init是一个守护进程，为了防止init的子进程成为僵尸进程(zombie process)，需要init在子进程在结束时获取子进程的结束码，通过结束码将程序表中的子进程移除，防止成为僵尸进程的子进程占用程序表的空间（程序表的空间达到上限时，系统就不能再启动新的进程了，会引起严重的系统问题）。</p>
<p><strong>信号处理主要工作：</strong></p>
<ul>
<li>初始化信号signal句柄</li>
<li>循环处理子进程</li>
<li>注册epoll句柄</li>
<li>处理子进程终止</li>
</ul>
<p>注:EPOLL类似于POLL，是Linux中用来做事件触发的，跟EventBus功能差不多。linux很长的时间都在使用select来做事件触发，它是通过轮询来处理的，轮询的fd数目越多，自然耗时越多，对于大量的描述符处理，EPOLL更有优势</p>
<p><strong>InstallSignalFdHandler</strong></p>
<p>在linux当中，父进程是通过捕捉SIGCHLD信号来得知子进程运行结束的情况，SIGCHLD信号会在子进程终止的时候发出，了解这些背景后，我们来看看init进程如何处理这个信号。</p>
<ol>
<li>新建一个sigaction结构体，sa_handler是信号处理函数，指向内核指定的函数指针SIG_DFL和Android 9.0及之前的版本不同，这里不再通过socket的读写句柄进行接收信号，改成了内核的信号处理函数SIG_DFL。</li>
<li>sigaction(SIGCHLD, &amp;act, nullptr) 这个是建立信号绑定关系，也就是说当监听到SIGCHLD信号时，由act这个sigaction结构体处理</li>
<li>RegisterHandler 的作用就是signal_read_fd（之前的s[1]）收到信号，触发handle_signal</li>
</ol>
<p>终上所述，InstallSignalFdHandler函数的作用就是，接收到SIGCHLD信号时触发HandleSignalFd进行信号处理</p>
<p>信号处理示意图：</p>
<p><img src="/images/20240225/20240225001.png"></p>
<p><strong>system/core/init/init.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">InstallSignalFdHandler</span><span class="params">(Epoll* epoll)</span> &#123;</span><br><span class="line">    <span class="comment">//SA_NOCLDSTOP使init进程只有在其进程终止时才会受到SIGCHLD信号</span></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span> &#123;</span> .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP &#125;;</span><br><span class="line">    sigaction(SIGCHLD, &amp;act, nullptr);</span><br><span class="line"> </span><br><span class="line">    <span class="type">sigset_t</span> mask;</span><br><span class="line">    sigemptyset(&amp;mask);</span><br><span class="line">    sigaddset(&amp;mask, SIGCHLD);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (!IsRebootCapable()) &#123;</span><br><span class="line">        <span class="comment">//如果init不具备CAP_SYS_BOOT的能力，则它此时正值容器中运行</span></span><br><span class="line">        <span class="comment">//在这种场景下，接收SIGTERM将会导致系统关闭</span></span><br><span class="line">        sigaddset(&amp;mask, SIGTERM);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (sigprocmask(SIG_BLOCK, &amp;mask, nullptr) == <span class="number">-1</span>) &#123;</span><br><span class="line">        PLOG(FATAL) &lt;&lt; <span class="string">&quot;failed to block signals&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//注册处理程序以解除对子进程中的信号的阻止</span></span><br><span class="line">    <span class="type">const</span> <span class="type">int</span> result = pthread_atfork(nullptr, nullptr, &amp;UnblockSignals);</span><br><span class="line">    <span class="keyword">if</span> (result != <span class="number">0</span>) &#123;</span><br><span class="line">        LOG(FATAL) &lt;&lt; <span class="string">&quot;Failed to register a fork handler: &quot;</span> &lt;&lt; strerror(result);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//创建信号句柄</span></span><br><span class="line">    signal_fd = signalfd(<span class="number">-1</span>, &amp;mask, SFD_CLOEXEC);</span><br><span class="line">    <span class="keyword">if</span> (signal_fd == <span class="number">-1</span>) &#123;</span><br><span class="line">        PLOG(FATAL) &lt;&lt; <span class="string">&quot;failed to create signalfd&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//信号注册，当signal_fd收到信号时，触发HandlerSignalFd</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">auto</span> result = epoll-&gt;RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) &#123;</span><br><span class="line">        LOG(FATAL) &lt;&lt; result.error();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>RegisterHandler</strong><br>说明：信号注册，把fd句柄加入到epoll_fd_的监听队列中<br><strong>system/core/init/epoll.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">Result&lt;<span class="type">void</span>&gt; <span class="title function_">Epoll::RegisterHandler</span><span class="params">(<span class="type">int</span> fd, Handler handler, <span class="type">uint32_t</span> events)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (!events) &#123;</span><br><span class="line">        <span class="keyword">return</span> Error() &lt;&lt; <span class="string">&quot;Must specify events&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">auto</span> sp = <span class="built_in">std</span>::make_shared&lt;decltype(handler)&gt;(<span class="built_in">std</span>::move(handler));</span><br><span class="line">    <span class="keyword">auto</span> [it, inserted] = epoll_handlers_.emplace(fd, <span class="built_in">std</span>::move(sp));</span><br><span class="line">    <span class="keyword">if</span> (!inserted) &#123;</span><br><span class="line">        <span class="keyword">return</span> Error() &lt;&lt; <span class="string">&quot;Cannot specify two epoll handlers for a given FD&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    epoll_event ev;</span><br><span class="line">    ev.events = events;</span><br><span class="line">    <span class="comment">// std::map&#x27;s iterators do not get invalidated until erased, so we use the</span></span><br><span class="line">    <span class="comment">// pointer to the std::function in the map directly for epoll_ctl.</span></span><br><span class="line">    ev.data.ptr = reinterpret_cast&lt;<span class="type">void</span>*&gt;(&amp;it-&gt;second);</span><br><span class="line">    <span class="comment">//将fd的可读事件加入到epoll_fd_的监听队列中</span></span><br><span class="line">    <span class="keyword">if</span> (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &amp;ev) == <span class="number">-1</span>) &#123;</span><br><span class="line">        Result&lt;<span class="type">void</span>&gt; result = ErrnoError() &lt;&lt; <span class="string">&quot;epoll_ctl failed to add fd&quot;</span>;</span><br><span class="line">        epoll_handlers_.erase(fd);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>HandlerSignalFd</strong><br>说明：监控SIGCHLD信号，调用ReapAnyOutstadingChildren来终止出现问题的子进程<br><strong>system/core/init/init.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">HandleSignalFd</span><span class="params">()</span> &#123;</span><br><span class="line">    signalfd_siginfo siginfo;</span><br><span class="line">    <span class="type">ssize_t</span> bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &amp;siginfo, <span class="keyword">sizeof</span>(siginfo)));</span><br><span class="line">    <span class="keyword">if</span> (bytes_read != <span class="keyword">sizeof</span>(siginfo)) &#123;</span><br><span class="line">        PLOG(ERROR) &lt;&lt; <span class="string">&quot;Failed to read siginfo from signal_fd&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//监控SIGCHLD信号</span></span><br><span class="line">    <span class="keyword">switch</span> (siginfo.ssi_signo) &#123;</span><br><span class="line">        <span class="keyword">case</span> SIGCHLD:</span><br><span class="line">            ReapAnyOutstandingChildren();</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> SIGTERM:</span><br><span class="line">            HandleSigtermSignal(siginfo);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            PLOG(ERROR) &lt;&lt; <span class="string">&quot;signal_fd: received unexpected signal &quot;</span> &lt;&lt; siginfo.ssi_signo;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ReapAnyOutstandingChildren</strong><br><strong>system/core/init/sigchld_handler.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">ReapAnyOutstandingChildren</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">while</span> (ReapOneProcess() != <span class="number">0</span>) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>最终会调用到ReapOneProcess()方法<br><strong>ReapOneProcess</strong><br>说明：ReapOneProcess是最终的处理函数，这个函数先调用waitpid找出挂掉进程的pid，然后根据pid找到对应Service，最后调用Service的Reap方法清除资源，根据进程对应的类型，决定是否重启机器或重启进程<br><strong>system/core/init/sigchld_handler.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">pid_t</span> <span class="title function_">ReapOneProcess</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">siginfo_t</span> siginfo = &#123;&#125;;</span><br><span class="line">    <span class="comment">//用waitpid函数获取状态发生变化的子进程pid</span></span><br><span class="line">    <span class="comment">//waitpid的标记为WNOHANG，即非阻塞，返回为正值就说明有进程挂掉了</span></span><br><span class="line">    <span class="keyword">if</span> (TEMP_FAILURE_RETRY(waitid(P_ALL, <span class="number">0</span>, &amp;siginfo, WEXITED | WNOHANG | WNOWAIT)) != <span class="number">0</span>) &#123;</span><br><span class="line">        PLOG(ERROR) &lt;&lt; <span class="string">&quot;waitid failed&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">auto</span> pid = siginfo.si_pid;</span><br><span class="line">    <span class="keyword">if</span> (pid == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">//当我们知道当前有一个僵尸pid，我们使用scopeguard来清除该pid</span></span><br><span class="line">    <span class="keyword">auto</span> reaper = make_scope_guard([pid] &#123; TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); &#125;);</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> name;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> wait_string;</span><br><span class="line">    Service* service = nullptr;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (SubcontextChildReap(pid)) &#123;</span><br><span class="line">        name = <span class="string">&quot;Subcontext&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//通过该pid找到对应的service</span></span><br><span class="line">        service = ServiceList::GetInstance().FindService(pid, &amp;Service::pid);</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">if</span> (service) &#123;</span><br><span class="line">            name = StringPrintf(<span class="string">&quot;Service &#x27;%s&#x27; (pid %d)&quot;</span>, service-&gt;name().c_str(), pid);</span><br><span class="line">            <span class="keyword">if</span> (service-&gt;flags() &amp; SVC_EXEC) &#123;</span><br><span class="line">                <span class="keyword">auto</span> exec_duration = boot_clock::now() - service-&gt;time_started();</span><br><span class="line">                <span class="keyword">auto</span> exec_duration_ms =</span><br><span class="line">                <span class="built_in">std</span>::chrono::duration_cast&lt;<span class="built_in">std</span>::chrono::milliseconds&gt;(exec_duration).count();</span><br><span class="line">                wait_string = StringPrintf(<span class="string">&quot; waiting took %f seconds&quot;</span>, exec_duration_ms / <span class="number">1000.0f</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (service-&gt;flags() &amp; SVC_ONESHOT) &#123;</span><br><span class="line">                <span class="keyword">auto</span> exec_duration = boot_clock::now() - service-&gt;time_started();</span><br><span class="line">                <span class="keyword">auto</span> exec_duration_ms =</span><br><span class="line">                <span class="built_in">std</span>::chrono::duration_cast&lt;<span class="built_in">std</span>::chrono::milliseconds&gt;(exec_duration)</span><br><span class="line">                .count();</span><br><span class="line">                wait_string = StringPrintf(<span class="string">&quot; oneshot service took %f seconds in background&quot;</span>,</span><br><span class="line">                    exec_duration_ms / <span class="number">1000.0f</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            name = StringPrintf(<span class="string">&quot;Untracked pid %d&quot;</span>, pid);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (siginfo.si_code == CLD_EXITED) &#123;</span><br><span class="line">        LOG(INFO) &lt;&lt; name &lt;&lt; <span class="string">&quot; exited with status &quot;</span> &lt;&lt; siginfo.si_status &lt;&lt; wait_string;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        LOG(INFO) &lt;&lt; name &lt;&lt; <span class="string">&quot; received signal &quot;</span> &lt;&lt; siginfo.si_status &lt;&lt; wait_string;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//没有找到service，说明已经结束了，退出</span></span><br><span class="line">    <span class="keyword">if</span> (!service) <span class="keyword">return</span> pid;</span><br><span class="line">    <span class="comment">//清除子进程相关的资源</span></span><br><span class="line">    service-&gt;Reap(siginfo);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (service-&gt;flags() &amp; SVC_TEMPORARY) &#123;</span><br><span class="line">        ServiceList::GetInstance().RemoveService(*service);<span class="comment">//移除该service</span></span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> pid;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="解析init-rc"><a href="#解析init-rc" class="headerlink" title="解析init.rc"></a>解析init.rc</h3><p>当属性服务建立完成后，init的自身功能基本就告一段落，接下来需要来启动其他的进程。但是init进程如何其他其他进程呢？其他进程都是一个二进制文件，我们可以直接通过exec的命令方式来启动，例如 ./system/bin/init second_stage，来启动init进程的第二阶段。但是Android系统有那么多的Native进程，如果都通过传exec在代码中一个个的来执行进程，那无疑是一个灾难性的设计。<br>init.rc是一个配置文件，内部由Android初始化语言编写（Android Init Language）编写的脚本。类似通过读取配置文件的方式，来启动不同的进程。</p>
<p><strong>LoadBootScripts</strong></p>
<p>说明：如果没有特殊配置ro.boot.init_rc，则解析./init.rc<br>把/system/etc/init、/system_ext/etc/init、/odm/etc/init、/product/etc/init这几个路径加入init.rc之后解析的路径，在init.rc解析完成后，解析这些目录里面rc文件<br>注意：init.rc位于/system/core/rootdir下<br><strong>system/core/init/init.cpp</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">LoadBootScripts</span><span class="params">(ActionManager&amp; action_manager, ServiceList&amp; service_list)</span> &#123;</span><br><span class="line">    Parser parser = CreateParser(action_manager, service_list);</span><br><span class="line"> </span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> bootscript = GetProperty(<span class="string">&quot;ro.boot.init_rc&quot;</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (bootscript.empty()) &#123;</span><br><span class="line">        parser.ParseConfig(<span class="string">&quot;/system/etc/init/hw/init.rc&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!parser.ParseConfig(<span class="string">&quot;/system/etc/init&quot;</span>)) &#123;</span><br><span class="line">            late_import_paths.emplace_back(<span class="string">&quot;/system/etc/init&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// late_import is available only in Q and earlier release. As we don&#x27;t</span></span><br><span class="line">        <span class="comment">// have system_ext in those versions, skip late_import for system_ext.</span></span><br><span class="line">        parser.ParseConfig(<span class="string">&quot;/system_ext/etc/init&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!parser.ParseConfig(<span class="string">&quot;/vendor/etc/init&quot;</span>)) &#123;</span><br><span class="line">            late_import_paths.emplace_back(<span class="string">&quot;/vendor/etc/init&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!parser.ParseConfig(<span class="string">&quot;/odm/etc/init&quot;</span>)) &#123;</span><br><span class="line">            late_import_paths.emplace_back(<span class="string">&quot;/odm/etc/init&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!parser.ParseConfig(<span class="string">&quot;/product/etc/init&quot;</span>)) &#123;</span><br><span class="line">            late_import_paths.emplace_back(<span class="string">&quot;/product/etc/init&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        parser.ParseConfig(bootscript);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Android7.0后，init.rc进行了拆分，每个服务都有自己的rc文件，他们基本上都被加载到/system/etc/init，/vendor/etc/init, /odm/etc/init等目录，等init.rc解析完成后，会来解析这些目录中的rc文件，用来执行相关的动作。</p>
<p><strong>CreateParser</strong><br>说明：创建Parser解析对象，例如service、on、import对象</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Parser <span class="title function_">CreateParser</span><span class="params">(ActionManager&amp; action_manager, ServiceList&amp; service_list)</span> &#123;</span><br><span class="line">    Parser parser;</span><br><span class="line"> </span><br><span class="line">    parser.AddSectionParser(<span class="string">&quot;service&quot;</span>, <span class="built_in">std</span>::make_unique&lt;ServiceParser&gt;(</span><br><span class="line">                            &amp;service_list, GetSubcontext(), <span class="built_in">std</span>::nullopt));</span><br><span class="line">    parser.AddSectionParser(<span class="string">&quot;on&quot;</span>, <span class="built_in">std</span>::make_unique&lt;ActionParser&gt;(&amp;action_manager, GetSubcontext()));</span><br><span class="line">    parser.AddSectionParser(<span class="string">&quot;import&quot;</span>, <span class="built_in">std</span>::make_unique&lt;ImportParser&gt;(&amp;parser));</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> parser;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>执行Action动作<br>按顺序把相关Action加入触发器队列，按顺序为 early-init -&gt; init -&gt; late-init. 然后在循环中，执行所有触发器队列中Action带Command的执行函数。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">am.QueueEventTrigger(<span class="string">&quot;early-init&quot;</span>);</span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;init&quot;</span>);</span><br><span class="line">am.QueueEventTrigger(<span class="string">&quot;late-init&quot;</span>);</span><br><span class="line">...</span><br><span class="line"><span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (!(waiting_for_prop || Service::is_exec_service_running())) &#123;</span><br><span class="line">            am.ExecuteOneCommand();</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="Zygote启动"><a href="#Zygote启动" class="headerlink" title="Zygote启动"></a>Zygote启动</h3><p>从Android 5.0的版本开始，Android支持64位的编译，因此zygote本身也支持32位和64位。通过属性ro.zygote来控制不同版本的zygote进程启动。<br>在init.rc的import段我们看到如下代码：<br><strong>system/core/rootdir/init.rc</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">import /system/etc/init/hw/init.$&#123;ro.zygote&#125;.rc <span class="comment">// 可以看出init.rc不再直接引入一个固定的文件，而是根据属性ro.zygote的内容来引入不同的文件</span></span><br></pre></td></tr></table></figure>
<p>init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。<br>分别是init.zygote32.rc，init.zygote32_64.rc，init.zygote64.rc，init.zygote64_32.rc，由硬件决定调用哪个文件。<br>这里拿64位处理器为例，init.zygote64.rc的代码如下所示：<br><strong>system/core/rootdir/init.zygote64.rc</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">main</span></span></span><br><span class="line"><span class="class">    <span class="title">priority</span> -20</span></span><br><span class="line"><span class="class">    <span class="title">user</span> <span class="title">root</span></span></span><br><span class="line"><span class="class">    <span class="title">group</span> <span class="title">root</span> <span class="title">readproc</span> <span class="title">reserved_disk</span></span></span><br><span class="line"><span class="class">    <span class="title">socket</span> <span class="title">zygote</span> <span class="title">stream</span> 660 <span class="title">root</span> <span class="title">system</span></span></span><br><span class="line"><span class="class">    <span class="title">socket</span> <span class="title">usap_pool_primary</span> <span class="title">stream</span> 660 <span class="title">root</span> <span class="title">system</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">exec_background</span> - <span class="title">system</span> <span class="title">system</span> -- /<span class="title">system</span>/<span class="title">bin</span>/<span class="title">vdc</span> <span class="title">volume</span> <span class="title">abort_fuse</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">write</span> /<span class="title">sys</span>/<span class="title">power</span>/<span class="title">state</span> <span class="title">on</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">restart</span> <span class="title">audioserver</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">restart</span> <span class="title">cameraserver</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">restart</span> <span class="title">media</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">restart</span> <span class="title">netd</span></span></span><br><span class="line"><span class="class">    <span class="title">onrestart</span> <span class="title">restart</span> <span class="title">wificond</span></span></span><br><span class="line"><span class="class">    <span class="title">writepid</span> /<span class="title">dev</span>/<span class="title">cpuset</span>/<span class="title">foreground</span>/<span class="title">tasks</span></span></span><br><span class="line"><span class="class">    <span class="title">critical</span> <span class="title">window</span>=</span>$&#123;zygote.critical_window.minute:-off&#125; target=zygote-fatal</span><br></pre></td></tr></table></figure>
<p>service zygote /system/bin/app_process64 -Xzygote /system/bin –zygote –start-system-server 解析：<br>service zygote ：init.zygote64.rc 中定义了一个zygote服务。 init进程就是通过这个service名称来创建zygote进程<br>/system/bin/app_process64 -Xzygote /system/bin –zygote –start-system-server解析：<br>zygote这个服务，通过执行进行/system/bin/app_process64 并传入4个参数进行运行：</p>
<table>
<thead>
<tr>
<th>名称</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>参数1</td>
<td>-Xzygote 该参数将作为虚拟机启动时所需的参数</td>
</tr>
<tr>
<td>参数2</td>
<td>/system/bin 代表虚拟机程序所在目录</td>
</tr>
<tr>
<td>参数3</td>
<td>–zygote 指明以ZygoteInit.java类中的main函数作为虚拟机执行入口</td>
</tr>
<tr>
<td>参数4</td>
<td>–start-system-server 告诉Zygote进程启动systemServer进程</td>
</tr>
</tbody></table>
<h3 id="init总结"><a href="#init总结" class="headerlink" title="init总结"></a>init总结</h3><p>init进程主要分为两个阶段，<br>第一个阶段主要完成了：</p>
<ul>
<li>创建文件系统目录，并挂载了相关文件系统</li>
<li>初始化了日志输出系统</li>
<li>加载了SELinux（访问控制安全模块）安全策略</li>
<li>进入第二阶段</li>
</ul>
<p>第二阶段主要完成了</p>
<ul>
<li>初始化了属性系统</li>
<li>执行了SELinux第二阶段，并恢复了一些文件的安全上下文</li>
<li>新建了epoll，并初始化了子进程终止信号处理函数</li>
<li>设置了系统其他属性，并开启了属性系统</li>
<li>解析init.rc来启动其他进程</li>
</ul>

      
      <blockquote>
        
        <strong>本文链接：</strong><br><a href="http://longzhiye.top/2024/02/25/2024-02-25/">http://longzhiye.top/2024/02/25/2024-02-25/</a>
      </blockquote>
    </div>
    <footer class="mdui-card-actions">
      
        <a class="mdui-ripple article_categories-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a>
      
      
        <a class="mdui-ripple article_tags-link" href="/tags/Android/" rel="tag">Android</a><a class="mdui-ripple article_tags-link" href="/tags/Linux/" rel="tag">Linux</a><a class="mdui-ripple article_tags-link" href="/tags/framework/" rel="tag">framework</a>
      
    </footer>
    
  </article>
  
<script src="//cdn.bootcdn.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js"></script>

  <script>$("#main article .mdui-card-content img.fancybox").on("click",function(e){$.fancybox.open({src:$(this).attr("src")});});</script>


  <nav id="paginator">
    
      <a rel="prev" class="extend prev" href="/2024/03/02/2024-03-02/">
        <button aria-label="prev" class="mdui-btn mdui-btn-raised mdui-btn-icon mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_back</i></button>
        <span class="mdui-p-x-3" mdui-tooltip="{content: 'Android 14 Zygote进程解析'}">上一篇</span>
      </a>
    
    <div class="spacer"></div>
    
      <a rel="next" class="extend next" href="/2024/02/24/2024-02-24/">
        <span class="mdui-p-x-3" mdui-tooltip="{content: 'Android 14 Handler 源码解析'}">下一篇</span>
        <button aria-label="next" class="mdui-btn mdui-btn-raised mdui-btn-icon mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_forward</i></button>
      </a>
    
  </nav>





</main>
  <footer id="footer" class="mdui-m-t-5 mdui-p-y-3 mdui-color-theme">
  <div class="mdui-p-y-0 mdui-text-center">
    
    
    
    
    
    
    
      <a href="http://github.com/longzhiye" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe7ab;</i></a>
    
    
    
      <a href="https://www.zhihu.com/people/long-zhi-xie-61" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe6c0;</i></a>
    
    
    
      <a href="tencent://tencent:////message/?uin=951898105&Menu=yes" target="_blank" class="mdui-btn mdui-btn-icon mdui-text-color-theme-a100"><i class="mdui-icon iconfont">&#xe651;</i></a>
    
    
  </div>
  <div class="mdui-p-y-1 mdui-text-center">
    Copyright &copy; 2022 - 2025 龙之叶<br>
    Powered by <a href="https://hexo.io/" target="_blank" class="mdui-text-color-theme-accent">Hexo</a>
    <br>
      <span id="busuanzi_container_site_pv" style="display: none;"><i class="iconfont">&#xe7fd;</i> <span id="busuanzi_value_site_pv"></span></span> &nbsp;&nbsp;
      <span id="busuanzi_container_site_uv" style="display: none;"><i class="iconfont">&#xe601;</i> <span id="busuanzi_value_site_uv"></span></span>
    
  </div>
</footer>

  <button id="gotop" class="mdui-fab mdui-fab-fixed mdui-fab-hide mdui-color-theme-accent mdui-ripple"><i class="mdui-icon material-icons">arrow_upward</i></button>
  <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
  
<script src="/js/mdui.js"></script>
<script src="/js/script.js"></script>

  
<script src="/custom.js"></script>

</body>
</html>
